package com.whf.android.jar.net;


import androidx.annotation.NonNull;

import com.whf.android.jar.app.Latte;
import com.whf.android.jar.net.callback.IError;
import com.whf.android.jar.net.callback.IFailure;
import com.whf.android.jar.net.callback.IRequest;
import com.whf.android.jar.net.callback.ISuccess;
import com.whf.android.jar.net.callback.RequestCallbacks;
import com.whf.android.jar.net.download.DownloadHandler;
import com.whf.android.jar.net.download.DownloadLangHandler;
import com.whf.android.jar.util.MediaTypeUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;

/**
 * 请求接口
 *
 * @author 傅令杰
 * @version 2017/4/2
 */

public final class RestClient {

    private final String URL;
    private final WeakHashMap<String, Object> HEADERS;
    ///参数
    private final WeakHashMap<String, Object> PARAMS;
    private final boolean JSON;
    private final IRequest REQUEST;
    private final String DOWNLOAD_DIR;
    private final String EXTENSION;
    private final String NAME;
    private final ISuccess SUCCESS;
    private final IFailure FAILURE;
    private final IError ERROR;
    private final RequestBody BODY;
    private final File FILE;
    private final WeakHashMap<String, String> FILE_SIGN;
    private final List<File> FILE_ARRAY;

    RestClient(String url,
               boolean json,
               WeakHashMap<String, Object> params,
               String downloadDir,
               String extension,
               String name,
               IRequest request,
               ISuccess success,
               IFailure failure,
               IError error,
               RequestBody body,
               File file,
               List<File> fileList,
               WeakHashMap<String, String> fileSign,
               WeakHashMap<String, Object> headers) {
        this.URL = url;
        this.JSON = json;
        this.PARAMS = params;
        this.DOWNLOAD_DIR = downloadDir;
        this.EXTENSION = extension;
        this.NAME = name;
        this.REQUEST = request;
        this.SUCCESS = success;
        this.FAILURE = failure;
        this.ERROR = error;
        this.BODY = body;
        this.FILE = file;
        this.FILE_ARRAY = fileList;
        this.FILE_SIGN = fileSign;
        this.HEADERS = headers;
    }

    @NonNull
    public static RestClientBuilder builder() {
        return new RestClientBuilder();
    }

    private void request(HttpMethod method) {
        String mediaType;
        final RestService service = RestCreator.getRestService();
        //有的项目附件不能传token
        final RestService upload = RestCreator.getDownloadRestService();
        final List<MultipartBody.Part> bodyArray;
        if (REQUEST != null) {
            REQUEST.onRequestStart();
        }
        Call<Object> call = null;
        switch (method) {
            case GET:
                call = service.get(URL, PARAMS);
                break;
            case NO_GET:
                call = upload.get(HEADERS, URL, PARAMS);
                break;
            case PART:
                call = service.part(URL, partMap());
                break;
            case NO_PART:
                call = upload.part(HEADERS, URL, partMap());
                break;
            case POST:
                call = service.post(URL, PARAMS);
                break;
            case NO_POST:
                call = upload.post(HEADERS, URL, PARAMS);
                break;
            case POST_QUERY:
                call = service.postQuery(URL, PARAMS);
                break;
            case NO_POST_QUERY:
                call = upload.postQuery(HEADERS, URL, PARAMS);
                break;
            case POST_RAW:
                call = service.postRaw(URL, BODY);
                break;
            case NO_POST_RAW:
                call = upload.postRaw(HEADERS, URL, BODY);
                break;
            case PUT:
                call = service.put(URL, PARAMS);
                break;
            case NO_PUT:
                call = upload.put(HEADERS, URL, PARAMS);
                break;
            case PUT_RAW:
                call = service.putRaw(URL, BODY);
                break;
            case NO_PUT_RAW:
                call = upload.putRaw(HEADERS, URL, BODY);
                break;
            case DELETE:
                call = service.delete(URL, PARAMS);
                break;
            case BITMAP:
                final MultipartBody.Part bodyBitmap =
                        MultipartBody.Part.createFormData(Latte.getUploadFile(), jpgName(), BODY);
                call = service.upload(URL, bodyBitmap);
                break;
            case UPLOAD:
                mediaType = MediaTypeUtils.getMediaType(FILE);
                //
                final RequestBody requestBody =
                        RequestBody.create(MediaType.parse(mediaType), FILE);
                final MultipartBody.Part body =
                        MultipartBody.Part.createFormData(Latte.getUploadFile(), FILE.getName(), requestBody);
                call = service.upload(URL, body);
                break;
            case UPLOAD_ARRAY:
                bodyArray = new ArrayList<>();
                if (FILE_ARRAY == null) {
                    throw new RuntimeException("params must be null!");
                }
                for (File file : FILE_ARRAY) {
                    mediaType = MediaTypeUtils.getMediaType(file);
                    final RequestBody requestBodyArray = RequestBody.create(MediaType.parse(mediaType), file);
                    bodyArray.add(MultipartBody.Part.createFormData(Latte.getUploadFiles(), file.getName(), requestBodyArray));
                }
                //
                call = service.upload(URL, bodyArray);
                break;
            case UPLOAD_MAP_FILE:
                bodyArray = new ArrayList<>();
                if (FILE_SIGN == null) {
                    throw new RuntimeException("params must be null!");
                }
                for (Map.Entry<String, String> file : FILE_SIGN.entrySet()) {
                    File fileSign = new File(file.getValue());
                    mediaType = MediaTypeUtils.getMediaType(fileSign);
                    final RequestBody requestBodyArray = RequestBody.create(MediaType.parse(mediaType), fileSign);
                    bodyArray.add(MultipartBody.Part.createFormData(file.getKey(), fileSign.getName(), requestBodyArray));
                }
                call = service.uploadMapFile(URL, bodyArray, partMap());
                break;
            case NO_BITMAP:
                final MultipartBody.Part bodyBitmapNo =
                        MultipartBody.Part.createFormData(Latte.getUploadFile(), jpgName(), BODY);
                call = upload.upload(URL, bodyBitmapNo);
                break;
            case NO_UPLOAD:
                mediaType = MediaTypeUtils.getMediaType(FILE);
                final RequestBody requestBodyNo =
                        RequestBody.create(MediaType.parse(mediaType), FILE);
                final MultipartBody.Part bodyNo =
                        MultipartBody.Part.createFormData(Latte.getUploadFile(), FILE.getName(), requestBodyNo);
                call = upload.uploadLang(HEADERS, URL, bodyNo);
                break;
            case NO_UPLOAD_ARRAY:
                bodyArray = new ArrayList<>();
                if (FILE_ARRAY == null) {
                    throw new RuntimeException("params must be null!");
                }
                for (File file : FILE_ARRAY) {
                    mediaType = MediaTypeUtils.getMediaType(file);
                    final RequestBody requestBodyArray = RequestBody.create(MediaType.parse(mediaType), file);
                    bodyArray.add(MultipartBody.Part.createFormData(Latte.getUploadFiles(), file.getName(), requestBodyArray));
                }
                call = upload.uploadLang(HEADERS, URL, bodyArray);
                break;
            case NO_UPLOAD_MAP_FILE:
                bodyArray = new ArrayList<>();
                if (FILE_SIGN == null) {
                    throw new RuntimeException("params must be null!");
                }
                for (Map.Entry<String, String> file : FILE_SIGN.entrySet()) {
                    File fileSign = new File(file.getValue());
                    mediaType = MediaTypeUtils.getMediaType(fileSign);
                    final RequestBody requestBodyArray = RequestBody.create(MediaType.parse(mediaType), fileSign);
                    bodyArray.add(MultipartBody.Part.createFormData(file.getKey(), fileSign.getName(), requestBodyArray));
                }
                call = upload.uploadMapFile(HEADERS, URL, bodyArray, partMap());
                break;
            default:
                break;
        }

        if (call != null) {
            call.enqueue(getRequestCallback());
        }
    }

    @NonNull
    Map<String, RequestBody> partMap() {
        Map<String, RequestBody> partMap = new HashMap<>();
        // 构建参数Map
        if (PARAMS != null) {
            for (Map.Entry<String, Object> entry : PARAMS.entrySet()) {
                partMap.put(entry.getKey(), RequestBody.create(MediaType.parse("text/plain"),
                        entry.getValue() + ""));
            }
        }
        return partMap;
    }

    @NonNull
    String jpgName() {
        //上传文件的名称
        long timestamp = System.currentTimeMillis();
        return "latte" + timestamp + ".jpg";
    }

    @NonNull
    private Callback<Object> getRequestCallback() {
        return new RequestCallbacks(
                JSON,
                REQUEST,
                SUCCESS,
                FAILURE,
                ERROR
        );
    }

    public final void get() {
        request(HttpMethod.GET);
    }

    public final void getNo() {
        request(HttpMethod.NO_GET);
    }

    public final void part() {
        request(HttpMethod.PART);
    }

    public final void partNo() {
        request(HttpMethod.NO_PART);
    }

    public final void post() {
        if (BODY == null) {
            request(HttpMethod.POST);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.POST_RAW);
        }
    }

    public final void postNo() {
        if (BODY == null) {
            request(HttpMethod.NO_POST);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.NO_POST_RAW);
        }
    }

    public final void query() {
        if (BODY == null) {
            request(HttpMethod.POST_QUERY);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.POST_RAW);
        }
    }

    public final void queryNo() {
        if (BODY == null) {
            request(HttpMethod.NO_POST_QUERY);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.NO_POST_RAW);
        }
    }

    public final void put() {
        if (BODY == null) {
            request(HttpMethod.PUT);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.PUT_RAW);
        }
    }

    public final void putNo() {
        if (BODY == null) {
            request(HttpMethod.NO_PUT);
        } else {
            if (!PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            request(HttpMethod.NO_PUT_RAW);
        }
    }

    public final void delete() {
        request(HttpMethod.DELETE);
    }

    public final void bitmap() {
        request(HttpMethod.BITMAP);
    }

    public final void bitmapNo() {
        request(HttpMethod.NO_BITMAP);
    }

    public final void upload() {
        request(HttpMethod.UPLOAD);
    }

    public final void uploadNo() {
        request(HttpMethod.NO_UPLOAD);
    }

    public final void uploads() {
        request(HttpMethod.UPLOAD_ARRAY);
    }

    public final void uploadNos() {
        request(HttpMethod.NO_UPLOAD_ARRAY);
    }

    /**
     * 带参数的上传文件
     */
    public final void uploadMapFile() {
        request(HttpMethod.UPLOAD_MAP_FILE);
    }

    /**
     * 带参数的上传文件
     */
    public final void uploadMapFileNo() {
        request(HttpMethod.NO_UPLOAD_MAP_FILE);
    }

    public final void download() {
        new DownloadHandler(URL, PARAMS, REQUEST, DOWNLOAD_DIR, EXTENSION, NAME,
                SUCCESS, FAILURE, ERROR)
                .handleDownload();
    }

    public final void downloadLang() {
        new DownloadLangHandler(URL, HEADERS, PARAMS, REQUEST, DOWNLOAD_DIR, EXTENSION, NAME,
                SUCCESS, FAILURE, ERROR)
                .handleDownload();
    }
}
